//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FXGE
 * @{
 */

/**
 * @file
 * @brief Device Independent Bitmap (DIB) Processing Engine.
 */
//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_DIB_H_
#define _FPDF_DIB_H_
#ifndef _FXCRT_EXTENSION_
	#include "../fxcrt/fx_ext.h"
#endif
//<<<+++OPENSOURCE_MUST_END

/** @brief DIBitmap formats. */
enum FXDIB_Format
{
	FXDIB_Invalid = 0,			/**< not a real format. */
	FXDIB_1bppMask = 0x101,		/**< 1bpp bitmask. 0 for zero alpha, 1 for maximum alpha. */
	FXDIB_1bppRgb = 0x001,		/**< 1bpp two color RGB bitmap. */
	FXDIB_1bppCmyk = 0x401,		/**< 1bpp two color CMYK bitmap. */
	FXDIB_8bppMask = 0x108,		/**< 8bpp alpha mask. */
	FXDIB_8bppRgb = 0x008,		/**< 8bpp 256 color RGB bitmap. */
	FXDIB_8bppRgba = 0x208,		/**< 8bpp 256 color RGB bitmap with extra alpha channel. */
	FXDIB_8bppCmyk = 0x408,		/**< 8bpp 256 color CMYK bitmap. */
	FXDIB_8bppCmyka = 0x608,	/**< 8bpp 256 color CMYK bitmap with extra alpha channel. */
	FXDIB_Rgb = 0x018,			/**< 24bpp RGB bitmap. Byte order: BGR. */
	FXDIB_Rgba = 0x218,			/**< 24bpp RGB bitmap with extra alpha channel. Byte order: BGR + 8bppMask. */
	FXDIB_Rgb32 = 0x020,		/**< 32bpp RGB bitmap. Byte order: BGR, 4th byte not used. */
	FXDIB_Argb = 0x220,			/**< 32bpp ARGB bitmap. Byte order: BGRA. */
	FXDIB_Cmyk = 0x420,			/**< 32bpp CMYK bitmap. Byte order: CMYK. */
	FXDIB_Cmyka = 0x620,		/**< 32bpp CMYKA bitmap with extra alpha channel. Byte order: CMYK + 8bppMask. */
};

/** @brief DIB channel ID. */
enum FXDIB_Channel
{
	FXDIB_Red = 1,		/**< Red channel. */
	FXDIB_Green,		/**< Green channel. */
	FXDIB_Blue,			/**< Blue channel. */
	FXDIB_Cyan,			/**< Cyan channel. */
	FXDIB_Magenta,		/**< Magenta channel. */
	FXDIB_Yellow,		/**< Yellow channel. */
	FXDIB_Black,		/**< Key Black channel. */
	FXDIB_Alpha			/**< Alpha channel. */
};

/**
 * @name Flags used for Stretch or Transform
 */
/*@{*/

/** @brief When set, don't do halftone for shrinking or rotating. */
#define FXDIB_DOWNSAMPLE		0x04
/** @brief When set, do interpolation for zooming. */
#define FXDIB_INTERPOL			0x20
/** @brief When set, do bicubic interpolation for zooming. */
#define FXDIB_BICUBIC_INTERPOL  0x80
/** @brief Don't do any interpolation for zooming or rotating. */
#define FXDIB_NOSMOOTH			0x100
/*@}*/ 

/**
 * @name Flags used for convert format
 */
/*@{*/
/** @brief When set, use the palette that builded from a bitmap. */
#define FXDIB_PALETTE_LOC		0x01

/** @brief When set, use the windows palette. */
#define FXDIB_PALETTE_WIN		0x02
/** @brief When set, use the mac palette. */
#define FXDIB_PALETTE_MAC		0x04

/*@}*/
/**
 * @name Constants for blending type. Undefined blend modes are not supported.
 *
 * @note
 * - B denotes blend function. It can be Normal, Multiply, Screen...
 * - Cr denotes result color components.
 * - Cb denotes background color components.
 * - Cs denotes source color components.
 */
/*@{*/

/**
 * @brief Selects the source color, ignoring the backdrop.\n
 * B(Cb, Cs) = Cs
 */
#define FXDIB_BLEND_NORMAL			0
/**
 * @brief Multiplies the backdrop and source color values.\n
 * B(Cb, Cs) = Cb * Cs
 */
#define FXDIB_BLEND_MULTIPLY		1
/**
 * @brief Multiplies the complements of the backdrop and source color values, then complements the result.\n
 * B(Cb, Cs) = 1 - [(1 - Cb) * (1 - Cs)] = Cb + Cs - Cb * Cs
 */
#define FXDIB_BLEND_SCREEN			2
/**
 * @brief Multiplies or screens the colors, depending on the backdrop color value.\n
 * B(Cb, Cs) = HardLight(Cs, Cb)
 */
#define FXDIB_BLEND_OVERLAY			3
/**
 * @brief Selects the darker of the backdrop and source colors.\n
 * B(Cb, Cs) = min(Cb, Cs)
 */
#define FXDIB_BLEND_DARKEN			4
/**
 * @brief Selects the lighter of the backdrop and source colors.\n
 * B(Cb, Cs) = max(Cb, Cs)
 */
#define FXDIB_BLEND_LIGHTEN			5
 /**
  * @brief Brightens the backdrop color to reflect the source color. Painting with black produces no changes.\n
  * B(Cb, Cs) = 
  * - min(1, Cb / (1 - Cs))		if Cs < 1
  * - 1							if Cs = 1
  */
#define FXDIB_BLEND_COLORDODGE		6
/**
 * @brief Darkens the backdrop color to reflect the source color. Painting with white produces no changes.\n
 * B(Cb, Cs) = 
 * - 1 - min(1, (1 - Cb) / Cs)	if Cs > 0
 * - 0							if Cs = 0
 */
#define FXDIB_BLEND_COLORBURN		7
/**
 * @brief Multiplies or screens the colors, depending on the source color value.\n
 * B(Cb, Cs) = 
 * - Multiply(Cb, 2 * Cs)		if Cs <= 0.5
 * - Screen(Cb, 2 * Cs - 1)		if Cs > 0.5
 */
#define FXDIB_BLEND_HARDLIGHT		8
/**
 * @brief Darkens or lightens the colors, depending on the source color value.\n
 * B(Cb, Cs) = 
 * - Cb - (1 - 2 * Cs) * Cb * (1 - Cb)		if Cs <= 0.5
 * - Cb + (2 * Cs - 1) * (D(Cb) - Cb)		if Cs > 0.5 \n
 * where D(x) = 
 * - ((16 * x - 12) * x + 4) * x			if x <= 0.25
 * - sqrt(x)								if x > 0.25
 */
#define FXDIB_BLEND_SOFTLIGHT		9
/**
 * @brief Subtracts the darker of the two constituent colors from the lighter color.\n
 * B(Cb, Cs) = |Cb - Cs|
 */
#define FXDIB_BLEND_DIFFERENCE		10
/**
 * @brief Produces an effect similar to that of the Difference mode but lower in contrast.\n
 * B(Cb, Cs) = Cb + Cs - 2 * Cb * Cs
 */
#define FXDIB_BLEND_EXCLUSION		11

/** @brief Standard nonseparable blend modes 
  * SetLum, Lum, SetSat, Sat defined in the p.524 of the pdf reference 1.7.  
  */
#define FXDIB_BLEND_NONSEPARABLE	21
/**
 * @brief Creates a color with the hue of the source color and the saturation and
 * luminosity of the backdrop color.
 * B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
 */
#define FXDIB_BLEND_HUE				21
/**
 * @brief Creates a color with the saturation of the source color and the hue and luminosity of the 
 * backdrop color. 
 * B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
 */
#define FXDIB_BLEND_SATURATION		22
/**
 * @brief Creates a color with the hue and saturation of the source color and the luminosity of the 
 * backdrop color.  
 * B(Cb, Cs) = SetLum(Cs, Lum(Cb))
 */
#define FXDIB_BLEND_COLOR			23
/**
 * @brief Creates a color with the luminosity of the source color and the hue and saturation of the 
 * backdrop color. 
 * B(Cb, Cs) = SetLum(Cb, Lum(Cs))
 */
#define FXDIB_BLEND_LUMINOSITY		24

/** @brief Unsupported blend type. */
#define FXDIB_BLEND_UNSUPPORTED		-1

/*@}*/ 

/** @brief ARGB color type. ((b) | ((g) << 8) | ((r) << 16)) | ((a) << 24) */
typedef FX_DWORD	FX_ARGB;
/** @brief RGB color type. ((r) | ((g) << 8) | ((b) << 16))*/
typedef FX_DWORD	FX_COLORREF;
/** @brief CMYK color type. ((k) | ((y) << 8) | ((m) << 16)) | ((c) << 24) */
typedef FX_DWORD	FX_CMYK;

class CFX_ClipRgn;
class CFX_DIBSource;
class CFX_DIBitmap;

/**
 * @brief The RGB macro selects a red, green, blue (RGB) color based on the arguments supplied
 * and the color capabilities of the output device.
 */
#define FXSYS_RGB(r, g, b)  ((r) | ((g) << 8) | ((b) << 16))
/** @brief Extract the red component. */
#define FXSYS_GetRValue(rgb) ((rgb) & 0xff)
/** @brief Extract the green component. */
#define FXSYS_GetGValue(rgb) (((rgb) >> 8) & 0xff)
/** @brief Extract the blue component. */
#define FXSYS_GetBValue(rgb) (((rgb) >> 16) & 0xff)

/**< @brief Get complementary-color, such as, Red vs Cyan, Green vs Magenta and Blue vs Yellow. */
#define FX_CCOLOR(val) (255-(val))
#define FXSYS_CMYK(c, m, y, k) (((c) << 24) | ((m) << 16) | ((y) << 8) | (k))
#define FXSYS_GetCValue(cmyk) ((FX_BYTE)((cmyk) >> 24) & 0xff)
#define FXSYS_GetMValue(cmyk) ((FX_BYTE)((cmyk) >> 16) & 0xff)
#define FXSYS_GetYValue(cmyk) ((FX_BYTE)((cmyk) >> 8) & 0xff)
#define FXSYS_GetKValue(cmyk) ((FX_BYTE)(cmyk) & 0xff)

#ifndef _FXM_OPENSOURCE_
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
#include "../fxhal/fxhal.h"
//<<<+++OPENSOURCE_MUST_END
#endif

/**
 * @name Helper for encoded color values
 * - ARGB:		0xaarrggbb
 * - CMYK:		0xccmmyykk
 * - COLORREF:	0x00bbggrr
 */
/*@{*/

/**
 * Decode a FX_CMYK to the cyan, magenta, yellow and black components.
 * 
 * @param[in] cmyk		The input FX_CMYK value.
 * @param[out] c		It receives the cyan component.
 * @param[out] m		It receives the magenta component.
 * @param[out] y		It receives the yellow component.
 * @param[out] k		It receives the black component.
 */
void CmykDecode(FX_CMYK cmyk, int& c, int& m, int& y, int& k);

/**
 * Encode a FX_CMYK from the cyan, magenta, yellow and black components.
 *
 * @param[in] c			The input cyan component.
 * @param[in] m			The input magenta component.
 * @param[in] y			The input yellow component.
 * @param[in] k			The input black component.
 * @return A FX_CMYK value.
 */
inline FX_CMYK CmykEncode(int c, int m, int y, int k) { return (c << 24) | (m << 16) | (y << 8) | k; }

/**
 * Decode a FX_ARGB to the alpha, red, green and blue components.
 * 
 * @param[in] argb		The input FX_ARGB value.
 * @param[out] a		It receives the alpha component.
 * @param[out] r		It receives the red component.
 * @param[out] g		It receives the green component.
 * @param[out] b		It receives the blue component.
 */
void ArgbDecode(FX_ARGB argb, int& a, int& r, int&g, int& b);
/**
 * Decode a FX_ARGB to the alpha and RGB values.
 *
 * @param[in] argb		The input FX_ARGB value.
 * @param[out] a		It receives the alpha component.
 * @param[out] rgb		It receives the RGB value. 
 */
void ArgbDecode(FX_ARGB argb, int& a, FX_COLORREF& rgb);

/**
 * Encode a FX_ARGB from the alpha, red, green, and blue components.
 *
 * @param[in] a			The input alpha component.
 * @param[in] r			The input red component.
 * @param[in] g			The input green component.
 * @param[in] b			The input blue component.
 * @return A FX_ARGB value.
 */
inline FX_ARGB ArgbEncode(int a, int r, int g, int b) { return (a << 24) | (r << 16) | (g << 8) | b; }
/**
 * Encode a FX_ARGB from the alpha and RGB values.
 *
 * @param[in] a			The input alpha component.
 * @param[in] rgb		The input RGB value.
 * @return A FX_ARGB value.
 */
FX_ARGB ArgbEncode(int a, FX_COLORREF rgb);

/*@}*/ 

/** @brief Extract the alpha component. */
#define FXARGB_A(argb) ((FX_BYTE)((argb) >> 24))
/** @brief Extract the red component. */
#define FXARGB_R(argb) ((FX_BYTE)((argb) >> 16))
/** @brief Extract the green component. */
#define FXARGB_G(argb) ((FX_BYTE)((argb) >> 8))
/** @brief Extract the blue component. */
#define FXARGB_B(argb) ((FX_BYTE)(argb))

/** @brief Create a FX_ARGB from the alpha, red, green, and blue components. */
#define FXARGB_MAKE(a,r,g,b) (((FX_DWORD)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
/** @brief Multiply with one alpha. */
#define FXARGB_MUL_ALPHA(argb, alpha) (((((argb) >> 24) * (alpha) / 255) << 24) | ((argb) & 0xffffff))

/** @brief Convert RGB to gray. */
#define FXRGB2GRAY(r,g,b) (((b) * 11 + (g) * 59 + (r) * 30) / 100)
/** @brief Convert CMYK to gray. */
#define FXCMYK2GRAY(c,m,y,k) (((255-(c)) * (255-(k)) * 30 + (255-(m)) * (255-(k)) * 59 + (255-(y)) * (255-(k)) * 11) / 25500)

/** @brief Alpha operator. */
#define FXDIB_ALPHA_MERGE(backdrop, source, source_alpha) (((backdrop) * (255-(source_alpha)) + (source)*(source_alpha))/255)
#define FXDIB_ALPHA_UNION(dest, src) ((dest) + (src) - (dest)*(src)/255)

/** @brief Get a FX_CMYK from a buffer. */
#define FXCMYK_GETDIB(p) ((((FX_LPBYTE)(p))[0] << 24 | (((FX_LPBYTE)(p))[1] << 16) | (((FX_LPBYTE)(p))[2] << 8) | ((FX_LPBYTE)(p))[3]))
#define FXCMYK_SETDIB(p, cmyk)  ((FX_LPBYTE)(p))[0] = (FX_BYTE)((cmyk) >> 24), \
								((FX_LPBYTE)(p))[1] = (FX_BYTE)((cmyk) >> 16), \
								((FX_LPBYTE)(p))[2] = (FX_BYTE)((cmyk) >> 8), \
								((FX_LPBYTE)(p))[3] = (FX_BYTE)(cmyk))


#if defined(_M_IX86) || defined(__i386__)
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/** @brief Get a FX_ARGB from a buffer. */
#define FXARGB_GETDIB(p) (*(FX_DWORD*)(p))
/** @brief Set a FX_ARGB to a buffer. */
#define FXARGB_SETDIB(p, argb) *(FX_DWORD*)(p) = argb
/** @brief Copy a FX_ARGB from a buffer to another. */
#define FXARGB_COPY(p1, p2) *(FX_DWORD*)(p1) = *(FX_DWORD*)(p2)

#define FXCMYK_COPY(p1, p2) *(FX_DWORD*)(p1) = *(FX_DWORD*)(p2)
//<<<+++OPENSOURCE_END
#else

#define FXARGB_GETDIB(p) (((FX_LPBYTE)(p))[0]) | (((FX_LPBYTE)(p))[1] << 8) | (((FX_LPBYTE)(p))[2] << 16) | (((FX_LPBYTE)(p))[3] << 24)
#define FXARGB_SETDIB(p, argb) ((FX_LPBYTE)(p))[0] = (FX_BYTE)(argb), \
							((FX_LPBYTE)(p))[1] = (FX_BYTE)((argb) >> 8), \
							((FX_LPBYTE)(p))[2] = (FX_BYTE)((argb) >> 16), \
							((FX_LPBYTE)(p))[3] = (FX_BYTE)((argb) >> 24)
#define FXARGB_COPY(dest, src) *(FX_LPBYTE)(dest) = *(FX_LPBYTE)(src), \
							*((FX_LPBYTE)(dest)+1) = *((FX_LPBYTE)(src)+1), \
							*((FX_LPBYTE)(dest)+2) = *((FX_LPBYTE)(src)+2), \
							*((FX_LPBYTE)(dest)+3) = *((FX_LPBYTE)(src)+3)

#define FXCMYK_COPY(dest, src)  *(FX_LPBYTE)(dest) = *(FX_LPBYTE)(src), \
								*((FX_LPBYTE)(dest)+1) = *((FX_LPBYTE)(src)+1), \
								*((FX_LPBYTE)(dest)+2) = *((FX_LPBYTE)(src)+2), \
								*((FX_LPBYTE)(dest)+3) = *((FX_LPBYTE)(src)+3)
#endif
/** @brief Set a FX_ARGB to a RGB byte-order buffer. */
#define FXARGB_SETRGBORDERDIB(p, argb) ((FX_LPBYTE)(p))[3] = (FX_BYTE)(argb>>24), \
	                        ((FX_LPBYTE)(p))[0] = (FX_BYTE)((argb) >> 16), \
	                        ((FX_LPBYTE)(p))[1] = (FX_BYTE)((argb) >> 8), \
							((FX_LPBYTE)(p))[2] = (FX_BYTE)(argb)
#define FXARGB_GETRGBORDERDIB(p) (((FX_LPBYTE)(p))[2]) | (((FX_LPBYTE)(p))[1] << 8) | (((FX_LPBYTE)(p))[0] << 16) | (((FX_LPBYTE)(p))[3] << 24)

/** @brief Copy from a BGR byte-order buffer to a RGB byte-order buffer. */
#define FXARGB_RGBORDERCOPY(dest, src) *((FX_LPBYTE)(dest)+3) = *((FX_LPBYTE)(src)+3), \
							*(FX_LPBYTE)(dest) = *((FX_LPBYTE)(src)+2), \
							*((FX_LPBYTE)(dest)+1) = *((FX_LPBYTE)(src)+1), \
							*((FX_LPBYTE)(dest)+2) = *((FX_LPBYTE)(src))
#ifdef _FX_MSB_FIRST_
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
/** Convert a FX_ARGB to 4-byte value of DIB-conversion byte-order. */
#define FXARGB_TODIB(argb) ((FX_BYTE)((argb) >> 24) | ((FX_BYTE)((argb) >> 16)) << 8 | ((FX_BYTE)((argb) >> 8)) << 16 | ((FX_BYTE)(argb) << 24))
/** Convert a FX_CMYK to 4-byte value of DIB-conversion byte-order. */
#define FXCMYK_TODIB(cmyk) (cmyk)
#define FXARGB_TOBGRORDERDIB(argb) ((FX_BYTE)(argb >> 24) | ((FX_BYTE)(argb >> 16)) << 24 | ((FX_BYTE)(argb >> 8)) << 16 | ((FX_BYTE)(argb) << 8))
//<<<+++OPENSOURCE_END
#else
#define FXARGB_TODIB(argb) (argb)
#define FXCMYK_TODIB(cmyk) ((FX_BYTE)((cmyk) >> 24) | ((FX_BYTE)((cmyk) >> 16)) << 8 | ((FX_BYTE)((cmyk) >> 8)) << 16 | ((FX_BYTE)(cmyk) << 24))
#define FXARGB_TOBGRORDERDIB(argb) ((FX_BYTE)(argb>>16) | ((FX_BYTE)(argb>>8)) << 8 | ((FX_BYTE)(argb)) << 16 | ((FX_BYTE)(argb>>24) << 24))
#endif

/**
 * @name Provide alpha flag quick access.
 */
/*@{*/

#define FXGETFLAG_COLORTYPE(flag)			(FX_BYTE)((flag)>>8)					/**< Get color type, It indicate whether cmyk or rgb. */
#define FXGETFLAG_ALPHA_FILL(flag)			(FX_BYTE)(flag)							/**< Get fill color alpha value if color type is cmyk. */
#define FXGETFLAG_ALPHA_STROKE(flag)		(FX_BYTE)((flag)>>16)					/**< Get stroke color alpha value if color type is cmyk. */

#define FXSETFLAG_COLORTYPE(flag, val)		flag = (((val)<<8)|(flag&0xffff00ff))	/**< Set color type, It indicate whether cmyk or rgb. */
#define FXSETFLAG_ALPHA_FILL(flag, val)		flag = ((val)|(flag&0xffffff00))		/**< Set fill color alpha value if color type is cmyk. */
#define FXSETFLAG_ALPHA_STROKE(flag, val)	flag = (((val)<<16)|(flag&0xff00ffff))	/**< Set stroke color alpha value if color type is cmyk. */

/*@}*/

/**
 * @brief An abstract class for DIB source, either from a in-memory bitmap, or from a compressed stream.
 * This class can't be constructed directly, instead, a derived class (like CFX_DIBitmap) should be used.
 *
 * We assume all color values in all bitmap formats are in Gray, RGB and CMYK color space.
 * If you operate two format DIB with different color space once, you need do color space transform using the context get from
 * ICodec_IccModule::CreateTransform_XXX or CFX_ColorMgr::GetTransform.
 */
class CFX_DIBSource : public CFX_Object
{
public:
	/** The virtual destructor. */
	virtual			~CFX_DIBSource();

	/**
	 * @name Get basic information
	 */
	/*@{*/

	/** Get the width of the bitmap. */
	int				GetWidth() const { return m_Width; }
	/** Get the height of the bitmap. */
	int				GetHeight() const { return m_Height; }
	/** Get the format of the bitmap. */
	FXDIB_Format	GetFormat() const { return (FXDIB_Format)(m_AlphaFlag * 0x100 + m_bpp); }
	/** Get the row pitch of the bitmap. */
	FX_DWORD		GetPitch() const { return m_Pitch; }

	/** 
	 *	Get the palette of the bitmap. 
	 *	In FXDIB_XXXa formats, the palette data not contain the alpha info, and
	 *	the real alpha channel should get from m_pAlphaMask.
	 *
	 * @return A pointer to palette buffer. ARGB or CMYK array.
	 */
	FX_DWORD*		GetPalette() const { return m_pPalette; }
	
	/*@}*/ 

	/**
	 * Get a buffer for whole DIB.
	 * Only in-memory DIB can supply such a buffer.
	 *
	 * @return A buffer for the whole DIB.
	 */
	virtual	FX_LPBYTE	GetBuffer() const { return NULL; }

	/**
	 * The virtual function that fetches a single scanline.
	 * Virtualize this function allows derived implementation of this class to adopt either a
	 * full buffer of the whole bitmap, or just buffer for one scan line.
	 *
	 * @param[in] line		The zero-based line number. [0, height).
	 * @return A pointer to the scanline.
	 */
	virtual FX_LPCBYTE	GetScanline(int line) const = 0;

	/**
	 * Skip to a scanline, progressively. Return TRUE for to be continued.
	 *
	 * @param[in] line		The zero-based line number.
	 * @param[in] pPause	Pointer to a pause object.
	 * @return Non-zero means to be continued, otherwise not to be continued.
	 */
	virtual FX_BOOL		SkipToScanline(int line, IFX_Pause* pPause) const { return FALSE; }

	/**
	 * Down sample a scanline, for quick stretching.
	 * The down-sampled result would be either 8bpp (for mask and grayscale), 24bpp or 32bpp.
	 *
	 * @param[in] line			The zero-based line number.
	 * @param[in,out] dest_scan	The destination scanline buffer to receive down-sample result.	
	 * @param[in] dest_bpp		The destination bits per pixel.
	 * @param[in] dest_width	The destination width of pixels in the scanline.
	 * @param[in] bFlipX		Whether to flip the bitmap in x-direction. 
	 * @param[in] clip_left		Clip start of the destination scanline.
	 * @param[in] clip_width	Clip width of the destination scanline.
	 */
	virtual void		DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
							int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const = 0;
	/**
	 * Pre-process for a down-sample operation.
	 *
	 * @param[in] width			The width of destination bitmap.
	 * @param[in] height		The height of destination bitmap.
	 */
	virtual void		SetDownSampleSize(int width, int height) const {}

	/**
	 * Get the number of BITS per pixel.
	 *
	 * @return The number of bits per pixel.
	 */
	int				GetBPP() const { return m_bpp; }

	/**
	 * Check whether the bitmap is an alpha mask (either 1bpp bitmask or 8bpp gray scale).
	 *
	 * @return Non-zero means an alpha mask, otherwise not.
	 */
	FX_BOOL			IsAlphaMask() const { return m_AlphaFlag == 1; }

	/**
	 * Check if it's a bitmap with alpha channel. NOTE: alpha masks return FALSE.
	 *
	 * @return Non-zero means it has a alpha channel, otherwise has not.
	 */
	FX_BOOL			HasAlpha() const { return m_AlphaFlag & 2 ? TRUE : FALSE; }

	/**
	 * Check if it's a solid (opaque) image.
	 *
	 * @return Non-zero means it is a solid (opaque) image, otherwise is not.
	 */
	FX_BOOL			IsOpaqueImage() const { return !(m_AlphaFlag & 3); }

	/**
	 * Check if it's a cmyk format image.
	 *
	 * @return Non-zero means it is a cmyk image, otherwise is not.
	 */
	FX_BOOL			IsCmykImage() const { return m_AlphaFlag & 4 ? TRUE : FALSE;}

	/**
	 * @name Get and set palette entry.
	 * Applicable to 1bppRgb and 8bppRgb formats.
	 */
	/*@{*/

	/**
	 * Get the number of palette entries.
	 *
	 * @return The number of palette entries.
	 */
	int				GetPaletteSize() const { return IsAlphaMask() ? 0 : (m_bpp == 1 ? 2 : (m_bpp == 8 ? 256 : 0)); }
	/**
	 * Get palette entry with specified palette entry index.
	 * In FXDIB_XXXa mode, the palette do not support alpha
	 *
	 * @param[in] index		Zero-based palette entry index of the palette.
	 * @return A palette entry value. The color type may be FX_ARGB or FX_CMYK depending on the dib format. 
	 */
	FX_DWORD		GetPaletteEntry(int index) const;

	/**
	 * Change a specified palette entry.
	 * In FXDIB_XXXa mode, the palette do not support alpha
	 *
	 * @param[in] index		Zero-based palette entry index of the palette.
	 * @param[in] color		The new value the entry. color type may be FX_ARGB or FX_CMYK depending on the dib format.
	 */
	void			SetPaletteEntry(int index, FX_DWORD color);

	FX_DWORD		GetPaletteArgb(int index) const { return GetPaletteEntry(index);}
	void			SetPaletteArgb(int index, FX_DWORD color) { SetPaletteEntry(index, color);}

	/**
	 * Copy from a palette buffer.
	 *
	 * @param[in] pSrcPal	The input palette. 
	 * @param[in] size    	The palette's size.
	 */
	void			CopyPalette(const FX_DWORD* pSrcPal, FX_DWORD size = 256);

	/*@}*/ 

	/**
	 * Clone a bitmap.
	 * Optionally a clipping region in bitmap coords can be specified to limit the size of result bitmap.
	 *
	 * @param[in] pClip		The clipping region of source bitmap.
	 * @return A cloned bitmap.
	 */
	CFX_DIBitmap*	Clone(const FX_RECT* pClip = NULL) const;

	/**
	 * Convert a bitmap, but clone first.
	 * Optionally a clipping region in bitmap coords can be specified to limit the size of result bitmap.
	 *
	 * @param[in] format	The destination bitmap format.
	 * @param[in] pClip		The clipping region of source bitmap.
	 * @param[in] pIccTransform		The color mapping context for source format to destination.
	 * @return A cloned and converted bitmap.
	 */
	CFX_DIBitmap*	CloneConvert(FXDIB_Format format, const FX_RECT* pClip = NULL, void* pIccTransform = NULL) const;

	/**
	 * Stretch this bitmap into a new bitmap with different size.
	 * - If dest width or dest height is negative, the bitmap will be flipped.
	 * - If a 1bpp bitmap is stretched, it will become either a RGB/CMYK bitmap, if it's a colored bitmap;
	 * or a 8bpp gray scale mask if it's a bitmask.
	 * 
	 * Stretching can be done in down-sample mode, which doesn't do interpolation so significantly faster
	 * especially when stretching big images into small ones.
	 *
	 * Optionally a clipping region in result bitmap coords can be specified to limit the size of result bitmap.
	 *
	 * @param[in] dest_width	The width of the destination bitmap.
	 * @param[in] dest_height	The height of the destination bitmap.
	 * @param[in] flags			Stretch flags, It can use #FXDIB_DOWNSAMPLE and #FXDIB_INTERPOL flags. 
	 * @param[in] pClip			The clipping region of destination bitmap.
	 * @return A stretched bitmap.
	 */
	CFX_DIBitmap*	StretchTo(int dest_width, int dest_height, FX_DWORD flags = 0, const FX_RECT* pClip = NULL) const;
	
	/**
	 * Transform this bitmap. A new transformed bitmap is returned.
	 * This bitmap can be colored bitmap, or an alpha mask. In case of colored bitmap,
	 * certain transformation (rotating or skewing) will cause the return bitmap as ARGB/CMYKa, no matter
	 * what the source bitmap format is.
	 * If a 1bpp bitmap is transformed, it will become either a RGB bitmap, if it's a colored bitmap;
	 * or a 8bpp gray scale mask if it's a bitmask.
	 * 
	 * The dimension of returned bitmap always match the dimension of the matrix.
	 * 
	 * Transformation can be done in down-sample mode, which doesn't do interpolation so significantly faster
	 * especially when transforming big images into small ones.
	 *
	 * Optionally a clipping region in result bitmap coords can be specified to limit the size of result bitmap.
	 *
	 * The position of left-top corner (in destination coords) of the result bitmap is also returned.
	 *
	 * @param[in] pMatrix	The transformation matrix.
	 * @param[out] left		It receives x-coordinate of the left-top corner of the result bitmap in destination coords.
	 * @param[out] top		It receives y-coordinate of the left-top corner of the result bitmap in destination coords.
	 * @param[in] flags		Stretch flags, It can use #FXDIB_DOWNSAMPLE and #FXDIB_INTERPOL flags.
	 * @param[in] pClip		The clipping region of destination bitmap.
	 * @return A transformed bitmap.
	 */
	CFX_DIBitmap*	TransformTo(const CFX_AffineMatrix* pMatrix, int& left, int &top, 
							FX_DWORD flags = 0, const FX_RECT* pClip = NULL) const;

	/**
	 * Get alpha mask from a bitmap. Returns a 8bpp alpha mask. not member variable m_pAlphaMask.
	 * Applicable to Argb format only. 
	 * Optionally a clipping region in bitmap coords can be specified to limit the size of result mask.
	 *
	 * @param[in] pClip		The clipping region of source bitmap.
	 * @return An alpha mask.
	 */
	CFX_DIBitmap*	GetAlphaMask(const FX_RECT* pClip = NULL) const;

	/**
	 * Copy extra alpha mask to this bitmap, the clipped input alpha mask must have same size as this bitmap. 
	 * Applicable to FXDIB_XXXa format only. 
	 * If this bitmap has already an extra alpha channel, then the previous alpha data will be replaced.
	 * The DIB format won't be changed.
	 *
	 * @param[in] pAlphaMask	The input 8bppMask bitmap. 
	 * @param[in] pClip			The clipping region of source bitmap.
	 * @return An alpha mask.
	 */
	FX_BOOL			CopyAlphaMask(const CFX_DIBSource* pAlphaMask, const FX_RECT* pClip = NULL);

	/**
	 * Swap X,Y coordinations of the bitmap. The image can also be flipped at the same time. 
	 * Optionally a clipping region (in destination bitmap coords) can be specified to limit the size of result.
	 * This function can be used to rotate the bitmap 90 or 270 degree.
	 * Suppose the original image has the following 4 pixels:
	 * +---+---+
	 * | 1 | 2 |
	 * +---+---+
	 * | 3 | 4 |
	 * +---+---+
	 * Then, depends on value of bXFlip and bYFlip, the result would look like this:
	 *
	 * if bXFlip = FALSE, bYFlip = FALSE:
	 * +---+---+
	 * | 1 | 3 |
	 * +---+---+
	 * | 2 | 4 |
	 * +---+---+
	 *
	 * if bXFlip = TRUE, bYFlip = FALSE:
	 * +---+---+
	 * | 3 | 1 |
	 * +---+---+
	 * | 4 | 2 |
	 * +---+---+
	 *
	 * if bXFlip = FALSE, bYFlip = TRUE:
	 * +---+---+
	 * | 2 | 4 |
	 * +---+---+
	 * | 1 | 3 |
	 * +---+---+
	 *
	 * if bXFlip = TRUE, bYFlip = TRUE:
	 * +---+---+
	 * | 4 | 2 |
	 * +---+---+
	 * | 3 | 1 |
	 * +---+---+
	 *
	 * @param[in] bXFlip	Whether to flip the bitmap in x-direction.
	 * @param[in] bYFlip	Whether to flip the bitmap in y-direction.
	 * @param[in] pClip		The clipping region of destination bitmap.
	 * @return A swapped bitmap.
	 */
	CFX_DIBitmap*	SwapXY(FX_BOOL bXFlip, FX_BOOL bYFlip, const FX_RECT* pClip = NULL) const;

	/**
	 * Flip image.
	 *
	 * @param[in] bXFlip	Whether to flip the bitmap in x-direction.
	 * @param[in] bYFlip	Whether to flip the bitmap in y-direction.
	 * @return A flipped bitmap.
	 */
	CFX_DIBitmap*	FlipImage(FX_BOOL bXFlip, FX_BOOL bYFlip) const;

	/**
	 * Get overlap rectangle.
	 *
	 * @note 
	 * - dest_left, dest_top, width, height pClipRgn are in destination area; m_nWidth and m_nHeight denote size of destination area;
	 * src_left, src_top, width, height, are in source area; src_width and src_height denote size of source area.
	 * - pixel(dest_left, dest_top) in destination and pixel(src_left, src_top) must overlap when do overlapping.
	 *
	 * @param[in,out] dest_left		Input x-coordinate of the left-top corner in destination; It receives x-coordinate of the left-top corner of overlap rectangle in destination area.
	 * @param[in,out] dest_top		Input y-coordinate of the left-top corner in destination; It receives y-coordinate of the left-top corner of overlap rectangle in destination area.
	 * @param[in,out] width			Input width; It receives the overlapped width.
	 * @param[in,out] height		Input height; It receives the overlapped height.
	 * @param[in] src_width			Input the source area width.
	 * @param[in] src_height		Input the source area height.
	 * @param[in,out] src_left		Input x-coordinate of the left-top corner in source; It receives x-coordinate of the left-top corner of overlap rectangle in source area.
	 * @param[in,out] src_top		Input y-coordinate of the left-top corner in source; It receives y-coordinate of the left-top corner of overlap rectangle in source area.
	 * @param[in] pClipRgn			The clipping region of destination area.
	 */
	void			GetOverlapRect(int& dest_left, int& dest_top, int& width, int& height, int src_width, 
						int src_height, int& src_left, int& src_top, const CFX_ClipRgn* pClipRgn);

	/** Must be 8bpp Mask. for extra alpha channel. */
	CFX_DIBitmap*	m_pAlphaMask;
protected:
	/** The constructor. This object can't be constructed directly. */
	CFX_DIBSource();

	/** The bitmap width. */
	int				m_Width;
	/** The bitmap height. */
	int				m_Height;
	/** Bits per pixel. */
	int				m_bpp;
	/** Alpha flag. 1: alpha mask; 2: has alpha; 4: cmyk. */
	FX_DWORD		m_AlphaFlag;
	/** Row pitch in bytes. */
	FX_DWORD		m_Pitch;
	/**
	 * ARGB or CMYK values for 1bpp and 8bpp bitmaps.
	 *
	 * @note: we may not always have this palette, in this case, the default
	 * palette is used. For 1bppRgb, the default palette is 0xff000000 and 0xffffffff;
	 * for 1bppCmyk, the default palette is 0x000000ff and 0x00000000;
	 * for 8bppRgb, the default palette starts from 0xff000000 to 0xffffffff;
	 * for 8bppCmyk, the default palette starts from 0x000000ff to 0x00000000
	 */
	FX_DWORD*		m_pPalette;

	/** Build the palette. */
	void			BuildPalette();

	/** Build the extra alpha channel. */
	FX_BOOL			BuildAlphaMask();

	/**
	 * Find a palette entry.
	 *
	 * @param[in] color	The entry value to be find. argb or cmyk
	 * @return The index of the found palette entry. -1 denotes found none.
	 */
	int				FindPalette(FX_DWORD color) const;
	/**
	 * Get the palette with specified alpha value for every palette entry.
	 * Applicable to 1bpp/8bppRgb(a) format only.
	 *
	 * @param[in,out] pal		It retrieves the palette.
	 * @param[in] alpha			The input alpha value.
	 */
	void			GetPalette(FX_DWORD* pal, int alpha) const;
};

/**
 * @brief Device Independent Bitmap Class.
 * DI Bitmap data are organized in FX_DWORD aligned scan lines, from top to bottom. 
 * Bitmap Coordinations: the bitmap coord has the origin at left-top corner.
 */
class CFX_DIBitmap : public CFX_DIBSource
{
public:
	/** The destructor. */
	virtual ~CFX_DIBitmap();

	/** Construct an empty bitmap. Application must call Create() or Copy(). */
	CFX_DIBitmap();

	/** Copy constructor. */
	CFX_DIBitmap(const CFX_DIBitmap& src);

	/**
	 * Actually create the DIB.
	 * Optionally the DIB can use external buffer provided by caller.
	 * This buffer should be kept by caller during the existence of the bitmap.
	 *
	 * @param[in] width			The width of the bitmap.
	 * @param[in] height		The height of the bitmap.
	 * @param[in] format		The format of the bitmap.
	 * @param[in] pBuffer		Not null to use external buffer.
	 * @param[in] pitch			Specified row pitch in bytes.
	 * @return TRUE for success, FALSE for failure.
	 */
	FX_BOOL			Create(int width, int height, FXDIB_Format format, FX_LPBYTE pBuffer = NULL, int pitch = 0);

	/**
	 * Copy from a DIB source, including bitmap info and all pixel data.
	 * This DIBitmap must be newly constructed.
	 *
	 * @param[in] pSrc			The DIB source.
	 */
	FX_BOOL			Copy(const CFX_DIBSource* pSrc);

	/**
	 * Get a buffer for whole DIB.
	 *
	 * @return A buffer for the whole DIB.
	 */
	virtual	FX_LPBYTE	GetBuffer() const { return m_pBuffer; }

	/**
	 * Fetches a single scanline.
	 * In FXDIB_XXXa mode, you should get alpha scanline individually from m_AlphaMask.
	 *
	 * @param[in] line		The zero-based line number. [0, height).
	 * @return A pointer to the scanline.
	 */
	virtual FX_LPCBYTE	GetScanline(int line) const { return m_pBuffer ? m_pBuffer + line * m_Pitch : NULL; }

	/**
	 * Down sample a scanline, for quick stretching.
	 * The down-sampled result would be either 8bpp (for mask and grayscale), 24bpp or 32bpp.
	 * In FXDIB_XXXa mode, you should do alpha scanline downsample individually from m_AlphaMask.
	 *
	 * @param[in] line			The zero-based line number.
	 * @param[in,out] dest_scan	The destination scanline buffer to receive down-sample result.	
	 * @param[in] dest_bpp		The destination bits per pixel. useless here.
	 * @param[in] dest_width	The destination width of pixels in the scanline.
	 * @param[in] bFlipX		Whether to flip the bitmap in x-direction. 
	 * @param[in] clip_left		Clip start of the destination scanline.
	 * @param[in] clip_width	Clip width of the destination scanline.
	 */
	virtual void	DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
							int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const;

	/**
	 * Takeover a bitmap. After taking-over, the source bitmap will contain an empty bitmap, and this bitmap
	 * will contain all data of the source bitmap.
	 *
	 * @param[in] pSrcBitmap	The input source bitmap.
	 */
	void			TakeOver(CFX_DIBitmap* pSrcBitmap);

	/**
	 * Convert a bitmap. All information in the old bitmap are retained.
	 *
	 * Supported conversion:
	 * - 1bppMask => 8bppMask; 
	 * - 1bppRgb => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 * - 1bppCmyk => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 * - 8bppRgb => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 * - 8bppCmyk => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 * - Rgb(a) => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 * - Rgb32 => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Argb / Cmyk(a) / 8bppMask
	 * - Argb => 8bppRgb(a) / 8bppCmyk(a) / Rgb(a) / Argb / Cmyk(a) / 8bppMask --> to non-alpha format, drop the alpha directly.
	 * - Cmyk(a) => 8bppRgb(a) / Rgb(a) / Rgb32 / Argb / Cmyk(a) / 8bppMask
	 *
	 * @param[in] format		The destination bitmap format.
	 * @param[in] pIccTransform	The color mapping context for source format to destination.
	 */
	FX_BOOL			ConvertFormat(FXDIB_Format format, void* pIccTransform = NULL);

	/**
	 * Fill the whole bitmap with specified color.
	 * For alpha mask bitmaps, only the alpha value is taken.
	 * In FXDIB_XXXa mode, you should do m_AlphaMask alpha clear individually.
	 *
	 * @param[in] color			The specified color to fill, argb or cmyk depending on format.
	 */
	void			Clear(FX_DWORD color);

	/**
	 * Get pixel ARGB or CMYK value.
	 * For alpha mask bitmaps, only the alpha value of returned value is valid. Argb format.
	 * In FXDIB_XXXa mode, you should do m_AlphaMask alpha get individually.
	 *
	 * @param[in] x			The x-coordiante in bitmap.
	 * @param[in] y			The y-coordinate in bitmap.
	 * @return The pixel ARGB or CMYK value depending on format.
	 */
	FX_DWORD		GetPixel(int x, int y) const;

	/**
	 * Set pixel ARGB or CMYK value.
	 * For alpha mask bitmaps, only the alpha value is taken.
	 * In FXDIB_XXXa mode, you should do m_AlphaMask alpha set individually.
	 *
	 * @param[in] x			The x-coordinate in bitmap.
	 * @param[in] y			The y-coordinate in bitmap.
	 * @param[in] argb		The input pixel ARGB or CMYK value depending on format.
	 */
	void			SetPixel(int x, int y, FX_DWORD color);

	/**
	 * Load a full channel from a source bitmap to this bitmap.
	 * The source bitmap can be any format, but must have specified source channel.
	 *
	 * If the destination channel is a color channel (R/G/B) in Rgb mode(and C/M/Y/K channel in CMYK mode),
	 * then the this bitmap must be a colored image.
	 * If the destination channel is the alpha channel, and this bitmap doesn't have an alpha channel, 
	 * it will be expanded with the alpha mask loaded. If this bitmap has already an alpha channel, 
	 * then the previous alpha data will be replaced.
	 *
	 * If the source bitmap doesn't have same size as this bitmap, the source bitmap will stretched
	 * to match the destination size before channel transferring.
	 *
	 * @param[in] destChannel		The destination channel.
	 * @param[in] pSrcBitmap		The DIB source.
	 * @param[in] srcChannel		The source channel.
	 */
	FX_BOOL			LoadChannel(FXDIB_Channel destChannel, const CFX_DIBSource* pSrcBitmap, FXDIB_Channel srcChannel);

	/**
	 * Set a full channel to specified value (0-255).
	 *
	 * If the destination channel is a color channel (R/G/B) in Rgb mode(and C/M/Y/K channel in CMYK mode),
	 * then the this bitmap must be a colored image.
	 * If the destination channel is the alpha channel, and this bitmap doesn't have an alpha channel, 
	 * it will be expanded with the alpha mask loaded. If this bitmap has already an alpha channel, 
	 * then the previous alpha data will be replaced.
	 *
	 * @param[in] destChannel		The destination channel.
	 * @param[in] value				The value to fill channel.
	 */
	FX_BOOL			LoadChannel(FXDIB_Channel destChannel, int value);

	/**
	 * Multiply alpha data with addition alpha (0-255).
	 * Applicable to all formats:
	 * -# If this is an alpha mask (1bppMask or 8bppMask), the result will be a 8bppMask with mask data modified;
	 * -# If this is an image without alpha channel, the bitmap will be expanded to include an alpha channel with new alpha data;
	 * -# If this is an image with alpha channel, then the alpha value will be multiplied into existing alpha data.
	 *
	 * @param[in] alpha				The alpha value to multiply with.
	 */
	FX_BOOL			MultiplyAlpha(int alpha);

	/**
	 * Multiply existing alpha data with another alpha mask.
	 *
	 * The source bitmap must be an alpha mask.
	 * 
	 * Applicable to all destination formats:
	 * -# If this is an alpha mask (1bppMask or 8bppMask), the result will be a 8bppMask with mask data multiplied;
	 * -# If this is an image without alpha channel, the bitmap will be expanded to include an alpha channel with new alpha data;
	 * -# If this is an image with alpha channel, then the alpha value will be multiplied into existing alpha data.
	 *
	 * If the source mask doesn't have same size as this bitmap, the source mask will stretched
	 * to match the destination size before multiplying.
	 *
	 * @param[in] pAlphaMask		The alpha mask to multiply with.
	 */
	FX_BOOL			MultiplyAlpha(const CFX_DIBSource* pAlphaMask);

	/**
	 * Transform pixels from another bitmap into specified position.
	 * The destination and source bitmaps can have different format, but need to be compatible.
	 * "width" and "height" parameters can not be negative. 
	 * Positions will be automatically clipped if out of source or destination bitmap region.
	 * The destination region will be replaced by data from the source bitmap.
	 *
	 * @param[in] dest_left			The x-coordinate in destination bitmap.
	 * @param[in] dest_top			The y-coordinate in destination bitmap.
	 * @param[in] width				The area width to transfer.
	 * @param[in] height			The area height to transfer.
	 * @param[in] pSrcBitmap		The DIB source.
	 * @param[in] src_left			The x-coordinate in source bitmap.
	 * @param[in] src_top			The y-coordinate in source bitmap.
	 * @param[in] pIccTransform		The color mapping context for source format to destination.
	 */
	FX_BOOL			TransferBitmap(int dest_left, int dest_top, int width, int height, 
							const CFX_DIBSource* pSrcBitmap, int src_left, int src_top, void* pIccTransform = NULL);

	/**
	 * Composite, blend and clipping source bitmap into this bitmap.
	 * 
	 * This bitmap can be Rgb/Rgba/Rgb32/Argb/Cmyk/Cmyka bitmap, and source bitmap can be any kind of bitmap (except masks).
	 * This bitmap can also be an 8bppMask, in this case only alpha channel from the source bitmap is composited.
	 * This bitmap can also be an 8bppRgb(a)/8bppCmyk(a) without palette, in this case no blending type supported.
	 *
	 * The clipping region should be specified in destination bitmap's coordination system.
	 * If the clipping region is NULL, then all pixels (in the specified portion) will be composited,
	 * otherwise, only those pixels in the portion will be composited.
	 *
	 * @param[in] dest_left			The x-coordinate in destination bitmap.
	 * @param[in] dest_top			The y-coordinate in destination bitmap.
	 * @param[in] width				The area width to composite.
	 * @param[in] height			The area height to composite.
	 * @param[in] pSrcBitmap		The DIB source.
	 * @param[in] src_left			The x-coordinate in source bitmap.
	 * @param[in] src_top			The y-coordinate in source bitmap.
	 * @param[in] blend_type		Blend type.
	 * @param[in] pClipRgn			The clipping region of destination bitmap.
	 * @param[in] pIccTransform		The color mapping context for source format to destination.
	 */
	FX_BOOL			CompositeBitmap(int dest_left, int dest_top, int width, int height, 
							const CFX_DIBSource* pSrcBitmap, int src_left, int src_top, 
							int blend_type = FXDIB_BLEND_NORMAL, const CFX_ClipRgn* pClipRgn = NULL, FX_BOOL bRgbByteOrder = FALSE, void* pIccTransform = NULL);

	/**
	 * Transfer (portion of) an alpha mask (with source color) to this bitmap.
	 * Applicable to Argb, Rgba and Cmyka formats only. The changed portion will be replaced (not blended).
	 * The pMask parameter must point to an alpha mask bitmap (1bppMask or 8bppMask).
	 *
	 * @param[in] dest_left			The x-coordinate in destination bitmap.
	 * @param[in] dest_top			The y-coordinate in destination bitmap.
	 * @param[in] width				The area width to transfer.
	 * @param[in] height			The area height to transfer.
	 * @param[in] pMask				The mask source.
	 * @param[in] color				The source color. FX_ARGB or FX_CMYK depending on the color type.
	 * @param[in] src_left			The x-coordinate in source bitmap.
	 * @param[in] src_top			The y-coordinate in source bitmap.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		The color mapping context for source format(color type describes in alpha_flag) to destination(this bitmap).
	 */
	FX_BOOL			TransferMask(int dest_left, int dest_top, int width, int height, 
							const CFX_DIBSource* pMask, FX_DWORD color, int src_left, int src_top, int alpha_flag = 0, void* pIccTransform = NULL);

	/**
	 * Composite (portion of) an alpha mask (with source color) into this bitmap.
	 * Applicable to 8bppMask/Rgb/Rgb32/Argb/Cmyk/Cmyka formats only.
	 * This bitmap can also be an 8bppRgb(a)/8bppCmyk(a) without palette, in this case no blending type supported.
	 *
	 * The pMask parameter must point to an alpha mask bitmap (1bppMask or 8bppMask).
	 *
	 * The clipping region should be specified in destination bitmap's coordination system.
	 * If the clipping region is NULL, then all pixels (in the specified portion) will be transferred,
	 * otherwise, only those pixels in the portion will be transferred.
	 *
	 * @param[in] dest_left			The x-coordinate in destination bitmap.
	 * @param[in] dest_top			The y-coordinate in destination bitmap.
	 * @param[in] width				The area width to composite.
	 * @param[in] height			The area height to composite.
	 * @param[in] pMask				The mask source.
	 * @param[in] color				The source color. FX_ARGB or FX_CMYK depending on the color type.
	 * @param[in] src_left			The x-coordinate in source bitmap.
	 * @param[in] src_top			The y-coordinate in source bitmap.
	 * @param[in] blend_type		Blend type.
	 * @param[in] pClipRgn			The clipping region of destination bitmap.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		The color mapping context for source format(color type describes in alpha_flag) to destination(this bitmap).
	 */
	FX_BOOL			CompositeMask(int dest_left, int dest_top, int width, int height, 
							const CFX_DIBSource* pMask, FX_DWORD color, int src_left, int src_top,
							int blend_type = FXDIB_BLEND_NORMAL, const CFX_ClipRgn* pClipRgn = NULL, FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL);

	/**
	 * Composite a fixed color into a rectangle area.
	 * Applicable to 8bppMask/Rgb/Rgb32/Argb/Cmyk/Cmyka formats only.
	 * This bitmap can also be an 8bppRgb(a)/8bppCmyk(a) without palette.
	 *
	 * @param[in] dest_left			The x-coordinate of the left-top corner.
	 * @param[in] dest_top			The y-coordinate of the left-top corner.
	 * @param[in] width				The area width.
	 * @param[in] height			The area height.
	 * @param[in] color				The fixed color. FX_ARGB or FX_CMYK depending on the color type.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		The color mapping context for source format(color type describes in alpha_flag) to destination(this bitmap).
	 */
	FX_BOOL			CompositeRect(int dest_left, int dest_top, int width, int height, FX_DWORD color, int alpha_flag = 0, void* pIccTransform = NULL);
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Gamma adjustment.
	 * Applicable to 8bpp Gray bitmap only.
	 *
	 * @param[in] bInvert			Whether reverse gamma adjustment or not.
	 */
	FX_BOOL			GammaAdjust(FX_BOOL bInvert);
//<<<+++OPENSOURCE_END
	/**
	 * Convert current bitmap to a colorscale bitmap. The DIB format won't be changed.
	 * Colorscale means all colors are a scale from forecolor to backcolor.
	 * If forecolor is black and backcolor is white, that's grayscale.
	 * Doesn't work with masks.
	 * @param[in] forecolor			The foreground color, FX_COLORREF or FX_CMYK depending on the DIB format.
	 * @param[in] backcolor			The background color, FX_COLORREF or FX_CMYK depending on the DIB format.
	 */
	FX_BOOL			ConvertColorScale(FX_DWORD forecolor, FX_DWORD backcolor);

	/**
	 * Floyd-Steinberg dithering for (portion of) the bitmap, using a palette. Now always FX_ARGB palette.
	 * IMPORTANT: currently only 8-bit grayscale bitmap is supported!
	 */
	FX_BOOL			DitherFS(const FX_DWORD* pPalette, int pal_size, const FX_RECT* pRect = NULL);


protected:
	/** The bitmap buffer. */
	FX_LPBYTE		m_pBuffer;
	/** Whether the bitmap uses external buffer. */
	FX_BOOL			m_bExtBuf;

	/** Convert bitmap to 256-level gray-scale data. In FXDIB_8bppMask format. */
	FX_BOOL			GetGrayData(void* pIccTransform = NULL);
};

/**
 * @brief Extracting portion of a DIB source. The result is always an in-memory DIB.
 */
class CFX_DIBExtractor : public CFX_Object
{
public:
	/** Construct from a DIB source. Do extracting. */
	CFX_DIBExtractor(const CFX_DIBSource* pSrc);
	/** The destructor. */
	~CFX_DIBExtractor();

	/** CFX_DIBitmap* type conversion operator. */
	operator CFX_DIBitmap*() { return m_pBitmap; }

private:
	/** The in-memory DIB. */
	CFX_DIBitmap*			m_pBitmap;
};

/** @brief Reference counted in-memory DIB type. */
typedef CFX_CountRef<CFX_DIBitmap> CFX_DIBitmapRef;

/**
 * @brief DIB Filter: a DIB based on another DIB. Two DIBs have exact same size and pixel order, but may have
 * different format. The filter translate each scanline of source.
 */
class CFX_FilteredDIB : public CFX_DIBSource
{
public:
	/** The constructor. */
	CFX_FilteredDIB();
	/** The destructor. */
	~CFX_FilteredDIB();

	/**
	 * Load filtered DIB's attributes from another DIB.
	 *
	 * @param[in] pSrc				The DIB source.
	 * @param[in] bAutoDropSrc		whether drop the source DIB automatically. 
	 */
	void					LoadSrc(const CFX_DIBSource* pSrc, FX_BOOL bAutoDropSrc = FALSE);

	/** Get destination format. */
	virtual FXDIB_Format	GetDestFormat() = 0;
	/** Get destination palette. */
	virtual FX_DWORD*		GetDestPalette() = 0;
	/** Get the extra alpha channel if exist. */
	//virtual CFX_DIBSource*	GetAlphaChannel() = 0;
	/**
	 * Translate a scanline.
	 *
	 * @param[out] dest_buf			Pointer to a destination scanline buffer.
	 * @param[in] src_buf			Pointer to a source scanline buffer.
	 */
	virtual void			TranslateScanline(FX_LPBYTE dest_buf, FX_LPCBYTE src_buf) const = 0;
	/**
	 * Translate downsamples.
	 *
	 * @param[out] dest_buf			Pointer to a destination scanline buffer.
	 * @param[in] src_buf			Pointer to a source scanline buffer.
	 * @param[in] pixels			The width in pixel to translate.
	 * @param[in] Bpp				The Bits per pixel.
	 */
	virtual void			TranslateDownSamples(FX_LPBYTE dest_buf, FX_LPCBYTE src_buf, int pixels, int Bpp) const = 0;

protected:
	virtual FX_LPCBYTE		GetScanline(int line) const;
	virtual void			DownSampleScanline(int line, FX_LPBYTE dest_scan, int dest_bpp,
								int dest_width, FX_BOOL bFlipX, int clip_left, int clip_width) const;

	/** The DIB source. */
	const CFX_DIBSource*	m_pSrc;
	/** Whether drop the source DIB automatically. */
	FX_BOOL					m_bAutoDropSrc;
	/** Cached */
	FX_LPBYTE				m_pScanline;
};

/**
 * @brief A scanline composer interface.
 */
class IFX_ScanlineComposer
{
public:
	/** 
	 * Compose scanline according to the source input scanline and extra alpha channel scanline.
	 *
	 * @param[in] line				The zero-based row index of the source bitmap.
	 * @param[in] scanline			Pointer to source scanline
	 * @param[in] scan_extra_alpha	Pointer to source extra alpha scanline if exist.
	 */
	virtual	void		ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha = NULL) = 0;
	
	/** 
	 * Initialize various kinds composer parameters.
	 *
	 * @param[in] width				The width of the source bitmap.
	 * @param[in] height			The height of the source bitmap.
	 * @param[in] src_format		The format of the source bitmap.
	 * @param[in] pSrcPalette		Pointer to source palette data to composite to the destination bitmap if exist.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL		SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette) = 0;
};

/**
 * @brief A scanline compositer.
 */
class CFX_ScanlineCompositor : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ScanlineCompositor();
	/** The destructor. */
	~CFX_ScanlineCompositor();

	/**
	 * Initialize the scanline compositor
	 *
	 * @param[in] dest_format		The destination bitmap format.
	 * @param[in] src_format		The source bitmap format.
	 * @param[in] pSrcPalette		Pointer to source palette, the palette entries whether FX_ARGB or FX_CMYK depending on the source bitmap format.
	 * @param[in] mask_color		The src color to mask. applicable src_format is 1/8bppMask. FX_ARGB or FX_CMYK depending on color type.
	 * @param[in] blend_type		Blend type. FXDIB_BLEND_XXX
	 * @param[in] bClip				The flag indicate the destination scanline is clipping.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		Pointer to the color mapping context for source format to destination if exist.
	 */
	FX_BOOL				Init(FXDIB_Format dest_format, FXDIB_Format src_format, FX_INT32 width, FX_DWORD* pSrcPalette,
							FX_DWORD mask_color, int blend_type, FX_BOOL bClip, FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL);


	
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** 
	 * The scanline composite routine, the source format must be Cmyk with bpp > 8
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source cmyk scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeCmykBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha, FX_LPBYTE dst_extra_alpha);
	//<<<+++OPENSOURCE_END
	/** 
	 * The scanline composite routine, the source format must be Rgb with bpp > 8
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source rgb scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeRgbBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha = NULL, FX_LPBYTE dst_extra_alpha = NULL);
	
	/** 
	 * The scanline composite routine, the source format must be 1/8bppPalette(1/8bppRgb(a) or 1/8bppCmyk(a)).
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source palette scanline, if source bitmap without palette, use default gray-scale palette.
	 *								See Init parameter pSrcPalette.
	 * @param[in] src_left			The source scanline column offset, only invalid in 1bpp.
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositePalBitmapLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan, 
											FX_LPCBYTE src_extra_alpha = NULL, FX_LPBYTE dst_extra_alpha = NULL);
	
	/** 
	 * The scanline composite routine, the source format must be 8bppMask, the source color is determined by mask_color.
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source 8bppMask scanline
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeByteMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, 
											FX_LPBYTE dst_extra_alpha = NULL);
	
	/** 
	 * The scanline composite routine, the source format must be 8bppMask, the source color is determined by mask_color.
	 *
	 * @param[in] dest_scan			Pointer to destination scanline to composite
	 * @param[in] src_scan			Pointer to source 1bppMask scanline
	 * @param[in] src_left			The source scanline column offset
	 * @param[in] width				The scanline width
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] dst_extra_alpha	Pointer to destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				CompositeBitMaskLine(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan, 
											FX_LPBYTE dst_extra_alpha = NULL);

protected:
	int					m_Transparency;		/**< Compositer selector */
	FXDIB_Format		m_SrcFormat,		/**< The source bitmap format */
						m_DestFormat;		/**< The destination bitmap format */
	FX_DWORD*			m_pSrcPalette;		/**< Can be ARGB palette, gray palette or CMYK palette. */
	
	int					m_MaskAlpha,		/**< Denote the alpha value of mask color. */
						m_MaskRed,			/**< Denote the Red value in RGB, the Cyan value in CMYK and the Gray value in color-scale. */
						m_MaskGreen,		/**< Denote the Green value in RGB, the Magenta value in CMYK. */
						m_MaskBlue,			/**< Denote the Blue value in RGB, the Yellow value in CMYK. */
						m_MaskBlack;		/**< Denote the Key-black value in CMYK. */

	int					m_BlendType;		/**< Blending type */
	void*				m_pIccTransform;	/**< Take the color mapping context for source format to destination. */
	FX_LPBYTE			m_pCacheScanline;	/**< The cache scanline used in transform. */
	int					m_CacheSize;		/**< The cache scanline size. */
	FX_BOOL             m_bRgbByteOrder;

#if !defined(_FXM_OPENSOURCE_) && defined(_FXM_SIMD_)
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
public:
	FX_INT32 GetTransparency() const {return m_Transparency;} 
	void* GetIccTransform() const {return m_pIccTransform;}
	FX_BOOL IsSupportSIMD () const;
	void CompositeCmykBitmapLine(CFXHAL_SIMDContext* simdContext, FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, FX_LPCBYTE src_extra_alpha, FX_LPBYTE dst_extra_alpha, FX_BOOL bSupportSIMD);
	void CompositeRgbBitmapLine(CFXHAL_SIMDContext* simdContext, FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, FX_LPCBYTE src_extra_alpha = NULL, FX_LPBYTE dst_extra_alpha = NULL, FX_BOOL bSupportSIMD = FALSE);
	void CompositePalBitmapLine(CFXHAL_SIMDContext* simdContext, FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan, FX_LPCBYTE src_extra_alpha = NULL, FX_LPBYTE dst_extra_alpha = NULL, FX_BOOL bSupportSIMD = FALSE);
	void CompositeByteMaskLine(CFXHAL_SIMDContext* simdContext, FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int width, FX_LPCBYTE clip_scan, FX_LPBYTE dst_extra_alpha = NULL, FX_BOOL bSupportSIMD = FALSE);
	void CompositeBitMaskLine(CFXHAL_SIMDContext* simdContext, FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int src_left, int width, FX_LPCBYTE clip_scan, FX_LPBYTE dst_extra_alpha = NULL, FX_BOOL bSupportSIMD = FALSE);
//<<<+++OPENSOURCE_MUST_END
#endif
};

/**
 * @brief Bitmap Composer: An implementation of scanline composer which 
 */
class CFX_BitmapComposer : public IFX_ScanlineComposer, public CFX_Object
{
public:
	/** The constructor. */
	CFX_BitmapComposer();
	/** The destructor. */
	~CFX_BitmapComposer();
	
	/** 
	 * Set the composite destination and parameters.
	 *
	 * @param[in] pDest				Pointer to destination bitmap, the scanline will composite to it,
	 *								Note: BitmapComposer needs the bitmap all the time, so the caller must keep the buffer.
	 * @param[in] pClipRgn			Pointer to clipping region of destination area if exist.
	 * @param[in] bitmap_alpha		Opacity of source bitmap
	 * @param[in] mask_color		The source color if source is an AlphaMask. FX_ARGB or FX_CMYK depending on the color type.
	 * @param[in] dest_rect			The clip rect of destination area.
	 * @param[in] bVertical			Whether need vertical render
	 * @param[in] blend_type		The blend type.	 
	 * @return TRUE for success, FALSE for failure.
	 */
	void				Compose(CFX_DIBitmap* pDest, const CFX_ClipRgn* pClipRgn, int bitmap_alpha, 
							FX_DWORD mask_color, FX_RECT& dest_rect, FX_BOOL bVertical, 
							FX_BOOL bFlipX, FX_BOOL bFlipY, FX_BOOL bRgbByteOrder = FALSE, 
							int alpha_flag = 0, void* pIccTransform = NULL, int blend_type = FXDIB_BLEND_NORMAL);

	/** 
	 * Init composite parameter.
	 *
	 * @param[in] width				The width of the source bitmap.
	 * @param[in] height			The height of the source bitmap.
	 * @param[in] src_format		The format of the source bitmap.
	 * @param[in] pSrcPalette		Pointer to source palette data to composite to the destination bitmap.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL		SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette);
	
	/** 
	 * Compose scanline according to the source input scanline and extra alpha channel scanline.
	 * The composer will select a proper compositer to do compose.
	 *
	 * @param[in] line				The zero-based row index of the source bitmap.
	 * @param[in] scanline			Pointer to source scanline
	 * @param[in] scan_extra_alpha	Pointer to source extra alpha scanline if exist.
	 */
	virtual	void		ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha);

protected:
	/** 
	 * Used by ComposeScanline.
	 *
	 * @param[in] dest_scan			Pointer to suitable destination scanline select from destination bitmap, may be vertical.
	 * @param[in] src_scan			Pointer to source scanline is specified by ComposeScanline
	 * @param[in] dest_width		The destination scanline length.
	 * @param[in] clip_scan			Pointer to scanline clip if exist.
	 * @param[in] src_extra_alpha	Pointer to source extra alpha scanline if exist(Such as FXDIB_XXXa).
	 * @param[in] dst_extra_alpha	Pointer destination extra alpha scanline to composite if exist(Such as FXDIB_XXXa).
	 */
	void				DoCompose(FX_LPBYTE dest_scan, FX_LPCBYTE src_scan, int dest_width, FX_LPCBYTE clip_scan, 
								FX_LPCBYTE src_extra_alpha = NULL, FX_LPBYTE dst_extra_alpha = NULL);

	CFX_DIBitmap*		m_pBitmap;		/**< The destination bitmap */
	const CFX_ClipRgn*	m_pClipRgn;		/**< The clipping region of destination bitmap. */
	FXDIB_Format		m_SrcFormat;	/**< The source bitmap format. */
	int					m_DestLeft, m_DestTop, m_DestWidth, m_DestHeight, m_BitmapAlpha;
	FX_DWORD			m_MaskColor;
	const CFX_DIBitmap*	m_pClipMask;
	CFX_ScanlineCompositor	m_Compositor;
	FX_BOOL				m_bVertical, m_bFlipX, m_bFlipY;
	int					m_AlphaFlag;
	void*				m_pIccTransform;
	FX_BOOL             m_bRgbByteOrder;
	int					m_BlendType;

	void				ComposeScanlineV(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha = NULL);
	FX_LPBYTE			m_pScanlineV, m_pClipScanV, m_pAddClipScan, m_pScanlineAlphaV;
#if !defined(_FXM_OPENSOURCE_) && defined(_FXM_SIMD_)
//<<<+++OPENSOURCE_MUST_BEGIN LIC==FOXIT
	CFXHAL_SIMDContext* m_pSimdContext;
	FX_BOOL m_bSupportSIMD;
//<<<+++OPENSOURCE_MUST_END
#endif
};

/**
 * @brief Bitmap Storer: An implementation of scanline composer which 
 *		  composing a bitmap storer to hold the source scanline data one by one.
 */
class CFX_BitmapStorer : public IFX_ScanlineComposer, public CFX_Object
{
public:
	/** The constructor. */
	CFX_BitmapStorer();
	/** The destructor. */
	~CFX_BitmapStorer();

	/** 
	 * Compose scanline according to the source input scanline and extra alpha channel scanline.
	 *
	 * @param[in] line				The zero-based row index of the source bitmap.
	 * @param[in] scanline			Pointer to source scanline
	 * @param[in] scan_extra_alpha	Pointer to source extra alpha scanline if exist.
	 */
	virtual	void		ComposeScanline(int line, FX_LPCBYTE scanline, FX_LPCBYTE scan_extra_alpha);

	/** 
	 * Actually create a bitmap storer.
	 *
	 * @param[in] width				The width of the bitmap.
	 * @param[in] height			The height of the bitmap.
	 * @param[in] src_format		The format of the bitmap.
	 * @param[in] pSrcPalette		Pointer to source palette data copy to the bitmap storer if exist.
	 * @return TRUE for success, FALSE for failure.
	 */
	virtual FX_BOOL		SetInfo(int width, int height, FXDIB_Format src_format, FX_DWORD* pSrcPalette);

	/**
	 * Get the Bitmap.
	 *
	 * @return the dib pointer.
	 */
	CFX_DIBitmap*		GetBitmap() { return m_pBitmap; }

	/**
	 * Detach the in-memory DIB from the bitmap storer.
	 * After this call, the caller is now responsible for releasing the bitmap.
	 */
	CFX_DIBitmap*		Detach();

	/** 
	 * Replace the bitmap storer with new in-memory DIB
	 */
	void				Replace(CFX_DIBitmap* pBitmap);

private:
	CFX_DIBitmap*		m_pBitmap;	/**< The in-memory DIB. */
};

/** @brief An internal stretch engine with interpolation. */
class CStretchEngine;

/** @brief A progressive bitmap stretch engine. */
class CFX_ImageStretcher : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ImageStretcher();
	/** The destructor. */
	~CFX_ImageStretcher();

	/**
	 * Stretch this bitmap into a new bitmap with different size.
	 * - If dest width or dest height is negative, the bitmap will be flipped.
	 * - If a 1bpp bitmap is stretched, it will become either a RGB/CMYK bitmap, if it's a colored bitmap;
	 * or a 8bpp gray scale mask if it's a bitmask.
	 *
	 * The stretcher is progressive. If Start success, then Continue
	 * should be called to finish the stretching (may need multiple calls).
	 *
	 * @param[in] pDest				The output stretched scanline composer.
	 * @param[in] pBitmap			The input colored or mask bitmap.
	 * @param[in] dest_width		The width of the destination bitmap.
	 * @param[in] dest_height		The height of the destination bitmap.
	 * @param[in] bitmap_rect		The clipping rect of destination bitmap.
	 * @param[in] flags				Stretch flags, It can use #FXDIB_DOWNSAMPLE and #FXDIB_INTERPOL flags.
	 * @return TRUE for to be continued.
	 */
	FX_INT32		Start(IFX_ScanlineComposer* pDest, const CFX_DIBSource* pBitmap, 
						int dest_width, int dest_height, const FX_RECT& bitmap_rect, FX_DWORD flags);
	
	/**
	 * Continue stretching.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return TRUE for to be continued.
	 */
	FX_INT32		Continue(IFX_Pause* pPause);

	IFX_ScanlineComposer*	m_pDest;		/**< The output stretched scanline composer. */
	const CFX_DIBSource*	m_pSource;		/**< The input colored or mask bitmap. */
	CStretchEngine*		m_pStretchEngine;	/**< An internal stretch engine with interpolation. */

	FX_DWORD		m_Flags;				/**< Stretch flags. */
	FX_BOOL			m_bFlipX,				/**< Stretch with x-coordinate flipping. */
					m_bFlipY;				/**< Stretch with y-coordinate flipping. */
	int				m_DestWidth,			/**< The stretched image width. */
					m_DestHeight;			/**< The stretched image height. */
	FX_RECT			m_ClipRect;				/**< The clipping rect of destination bitmap. */
	int				m_LineIndex;			/**< The zero-based line index of destination bitmap. */
	int				m_DestBPP;				/**< The number of BITS per pixel of destination bitmap. */
	FX_LPBYTE		m_pScanline;			/**< Temporary scanline of source bitmap after stretch. */
	FX_LPBYTE       m_pMaskScanline;		/**< Temporary extra alpha scanline of source bitmap after stretch if exist. */
	FXDIB_Format	m_DestFormat;			/**< The stretched bitmap format. */
	FX_INT32		m_Status;				/**< The stretch status. */

	/** 
	 * Start quick stretch with downsample. 
	 * 
	 * @return TRUE for to be continued.
	 */
	FX_INT32		StartQuickStretch();
	/** 
	 * Start stretch with interpolation, use CStretchEngine. 
	 * @return TRUE for to be continued.
	 */
	FX_INT32		StartStretch();

	/**
	 * Continue stretching with downsample.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return TRUE for to be continued.
	 */
	FX_INT32		ContinueQuickStretch(IFX_Pause* pPause);

	/**
	 * Continue stretching with interpolation.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return TRUE for to be continued.
	 */
	FX_INT32		ContinueStretch(IFX_Pause* pPause);
};

/** @brief A progressive bitmap transform engine. */
class CFX_ImageTransformer : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ImageTransformer();
	/** The destructor. */
	~CFX_ImageTransformer();

	/**
	 * Transform a DIB (colored or mask) with explicit matrix. 
	 * A new transformed bitmap is created and maintained by CFX_BitmapStorer.
	 * This bitmap can be colored bitmap, or an alpha mask. In case of colored bitmap,
	 * certain transformation (rotating or skewing) will cause the bitmap storer as ARGB/CMYKa, no matter
	 * what the source bitmap format is.
	 * If a 1bpp bitmap is transformed, it will become either a RGB/CMYK bitmap, if it's a colored bitmap;
	 * or a 8bpp gray scale mask if it's a bitmask.
	 *
	 * Now this process can be progressive. If Start success, then Continue
	 * should be called to finish the stretching (may need multiple calls).
	 *
	 * @param[in] pSrc				The input colored or mask bitmap.
	 * @param[in] pMatrix			The matrix used to output the bitmap.
	 * @param[in] flags				The stretching flags.
	 * @param[in] pClip				The clipping rect of destination bitmap.
	 * @return TRUE for to be continued.
	 */
	FX_INT32	Start(const CFX_DIBSource* pSrc, const CFX_AffineMatrix* pMatrix, int flags, const FX_RECT* pClip);
	
	/**
	 * Continue stretching.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return TRUE for to be continued.
	 */
	FX_INT32	Continue(IFX_Pause* pPause);

	CFX_AffineMatrix* m_pMatrix;	/**< The transformation matrix. */
	FX_RECT		m_StretchClip;
	int			m_ResultLeft, m_ResultTop, m_ResultWidth, m_ResultHeight;
	CFX_AffineMatrix	m_dest2stretch;
	CFX_ImageStretcher	m_Stretcher;
	CFX_BitmapStorer	m_Storer;
	FX_DWORD	m_Flags;
	int			m_Status;				/**< Internal status flag. */
};

/** @brief A progressive bitmap rendering engine. */
class CFX_ImageRenderer : public CFX_Object
{
public:
	/** The constructor. */
	CFX_ImageRenderer();
	/** The destructor. */
	~CFX_ImageRenderer();

	/**
	 * Shortcut for rendering a DIB (colored or mask) with explicit matrix.
	 *
	 * Now this process can be progressive. If Start success, then Continue
	 * should be called to finish the rendering (may need multiple calls).
	 *
	 * @param[in] pDevice			The device gray,mask or colored bitmap.
	 * @param[in] pClipRgb			The clipping region of destination bitmap.
	 * @param[in] pSource			The input colored or mask bitmap.
	 * @param[in] bitmap_alpha		The constant alpha for the bitmap.
	 * @param[in] mask_color		The color to be masked.
	 * @param[in] pMatrix			The matrix used to output the bitmap.
	 * @param[in] dib_flags			The stretching flags.
	 * @param[in] alpha_flag		The flag indicate color type and alpha value, alpha_flag == (color_type<<8)|alpha
	 *								color type: 0 for rgb, 1 for cmyk
	 * @param[in] pIccTransform		The color mapping context for source format(color type describes in alpha_flag) to destination(this bitmap).
	 * @param[in] blend_type		The blend type.
	 * @return the status describes in FXDIB_PROGRESSIVE_XXX
	 */
	FX_INT32			Start(CFX_DIBitmap* pDevice, const CFX_ClipRgn* pClipRgn, 
							const CFX_DIBSource* pSource, int bitmap_alpha,
							FX_DWORD mask_color, const CFX_AffineMatrix* pMatrix, FX_DWORD dib_flags,
							FX_BOOL bRgbByteOrder = FALSE, int alpha_flag = 0, void* pIccTransform = NULL,
							int blend_type = FXDIB_BLEND_NORMAL);
	/**
	 * Continue rendering.
	 *
	 * @param[in] pPause			The pause interface.
	 * @return the status describes in FXDIB_PROGRESSIVE_XXX
	 */
	FX_INT32			Continue(IFX_Pause* pPause);

protected:
	CFX_DIBitmap*		m_pDevice;
	const CFX_ClipRgn*	m_pClipRgn;
	int					m_BitmapAlpha;
	FX_DWORD			m_MaskColor;
	CFX_AffineMatrix	m_Matrix;
	CFX_ImageTransformer*	m_pTransformer;
	CFX_ImageStretcher	m_Stretcher;
	CFX_BitmapComposer	m_Composer;
	int					m_Status;
	int					m_DestLeft, m_DestTop;
	FX_RECT				m_ClipBox;
	FX_DWORD			m_Flags;
	int					m_AlphaFlag;
	void*				m_pIccTransform;
	FX_BOOL				m_bRgbByteOrder;
	int					m_BlendType;
};
//<<<+++OPENSOURCE_MUST_BEGIN
#endif // _FPDF_DIB_H_
//<<<+++OPENSOURCE_MUST_END
/** @} */
